#pragma once
#include "Comm.h"

namespace COMM
{
	template<class T>
	class list
	{
	public:
		class iterator
		{
		public:
			iterator():m_pVal(NULL),m_pNext(NULL),m_pPre(NULL){}
			explicit iterator(T* pVal)
				: m_pVal(pVal)
				, m_pNext(NULL)
				, m_pPre(NULL) {}
			~iterator() {}

			T& operator*() { return *m_pVal;}
			const T& operator*() const { return *m_pVal;}

			const iterator& operator++()
			{
				MYLIB_ASSERT_NOTNULL(m_pNext);
				*this = *m_pNext;
				return *this;
			}
			iterator operator++(int)
			{
				iterator tmp = *this;
				++(*this);
				return tmp;
			}
			const iterator& operator--()
			{
				MYLIB_ASSERT_NOTNULL(m_pPre);
				*this = *m_pPre;
				return *this;
			}
			iterator operator--(int)
			{
				iterator tmp = *this;
				--(*this);
				return tmp;
			}
			bool operator==(const iterator& itor) const 
			{  
				// compare the memory address but not the actual value.
				return (m_pVal == itor.m_pVal);
			}  
			bool operator!=(const iterator& itor) const 
			{  
				return (m_pVal != itor.m_pVal);
			}

		private:
			friend class list;
			T* m_pVal;
			iterator* m_pNext;
			iterator* m_pPre;
		};



		list(): m_head(NULL), m_size(0)
		{
			m_head = new iterator((T*)&m_size);
			MYLIB_ASSERT_NOTNULL(m_head);
			m_head->m_pNext = m_head;
			m_head->m_pPre = m_head;
		}

		// deep copy.
		list(const list& lst): m_head(NULL), m_size(0)
		{
			m_head = new iterator((T*)&m_size);
			MYLIB_ASSERT_NOTNULL(m_head);
			m_head->m_pNext = m_head;
			m_head->m_pPre = m_head;
			for (iterator itor = lst.begin(); itor != lst.end(); itor++)
			{
				push_back(*itor);
			}
		}

		list& operator=(const list& lst)
		{
			if(m_head != lst.m_head)
			{
				clear();
				for (iterator itor = lst.begin(); itor != lst.end(); itor++)
				{
					push_back(*itor);
				}
			}
			return *this;
		}

		virtual ~list() 
		{
			clear();
			delete m_head;
			m_head = NULL;
			MYLIB_ASSERT(0 == m_size);	
		}

		const iterator& begin() const
		{
			return *m_head->m_pNext;
		}

		const iterator& end() const
		{
			return *m_head;
		}

		int size() const
		{
			return m_size;
		}

		bool empty() const
		{
			return (0 == size());
		}

		// inserts before itor.
		const iterator& insert(iterator itor, const T& val)
		{
			T* pVal = new T(val);
			MYLIB_ASSERT_NOTNULL(pVal);
			iterator* itor_new = new iterator(pVal);
			MYLIB_ASSERT_NOTNULL(itor_new);

			iterator* front = itor.m_pPre;
			iterator* back = front->m_pNext;
			itor_new->m_pPre = front;
			itor_new->m_pNext = back;
			front->m_pNext = itor_new;
			back->m_pPre = itor_new;
			++m_size;
			return *itor_new;
		}

		void push_back(const T& val)
		{
			insert(this->end(),val);
		}

		void push_front(const T& val)
		{
			insert(this->begin(),val);
		}

		const iterator& erase(iterator itor)
		{
			// can not erase m_head.
			if (itor == this->end())
			{
				MYLIB_ASSERT(!"can not erase the ended list iterator.");
			}
			iterator* front = itor.m_pPre;
			// actual iterator address.
			iterator* itor_del = front->m_pNext;
			iterator* back = itor.m_pNext;
			front->m_pNext = back;
			back->m_pPre = front;
			{
				// release memory.
				delete itor_del->m_pVal;
				delete itor_del;
			}
			--m_size;
			return *back;
		}

		void remove(const T& val)
		{
			for (iterator itor = this->begin(); itor != this->end(); itor++)
			{
				if (val == *itor)
				{
					erase(itor);
					return;
				}
			}
		}

		void clear()
		{
			for (iterator itor = this->begin(); itor != this->end(); )
			{
				itor = erase(itor);
			}
		}

		void reverse()
		{
			iterator* pos = m_head;
			do 
			{
				iterator* next = pos->m_pNext;
				{
					pos->m_pPre = next;
				}
				pos = next;
			} while (pos != m_head);

			do
			{
				iterator* pre = pos->m_pPre;
				{
					pre->m_pNext = pos;
				}
				pos = pre;
			} while (pos != m_head);
		}

	private:
		int m_size;
		iterator* m_head;

	};


	template<class T>
	class stdlist : 
#if (COMM_FEATURE_STDLIST==1)
		public std::list<T>
#else
		public COMM::list<T>
#endif
	{
	public:
#if (COMM_FEATURE_STDLIST==1)
		typedef typename std::list<T>::iterator iterator;
#else
		typedef typename COMM::list<T>::iterator iterator;
#endif
		T& at(int index)
		{
			int i = 0;
			int count = this->size();
			MYLIB_ASSERT(index >= 0 && index < count);
			for (iterator itor = this->begin(); itor != this->end(); itor++)
			{
				if(i == index)
					return *itor;
				i++;
			}
			iterator itor_ = this->end();
			return *itor_;
		}

		T& operator[](int index)
		{
			return this->at(index);
		}

		stdlist& operator<<(const T& val)
		{
			this->push_back(val);
			return *this;
		}

	};
}


#define foreach(T,var,lst)	\
	T var; stdlist<T>::iterator itor_##var = lst.begin();	\
	for(;itor_##var!=lst.end() && ((var=*itor_##var) || true);itor_##var++)


